<?php
namespace App\Service\AuthService;

use App\Service\BaseService;
use App\Service\Code\Normal;
use App\Service\TaskServer\TaskWorker;
use Service\AppService\IdService;
use App\Service\AppService\SystemCacheConfigService;

/**
 * 二要素认证
 * @author: hj
 */
class IdCardVerifyService extends BaseService {

    //腾讯接口验证
    const AUTH_TENCENT = 'auth_tencent';

    public static $authList = [
        'auth',//创蓝接口验证
        'auth_tencent',//腾讯接口验证
    ];

    /**
     * 二要素验证
     * @param array $param
     * @return array
     */
    public static function auth(array $param) {
        if (empty($param['name'])) {
            return Normal::returnCode(Normal::FAIL, "except name");
        }

        if (empty($param['idNum'])) {
            return Normal::returnCode(Normal::FAIL, "except idcard");
        }
        //获取系统配置
        $auth_config = SystemCacheConfigService::instance()->getCacheInfoBySystemCode('auth_config');
        if (empty($auth_config)) {
            //默认实用创蓝235 验证
            return self::chuanglanAuth($param);
        } else {
            $config = SystemCacheConfigService::instance()->getCacheInfoBySystemCode($auth_config['auth_way']);
            if (empty($config)) {
                //默认实用创蓝235 验证
                return self::chuanglanAuth($param);
            }
            if (!in_array($auth_config['auth_way'], self::$authList)) {
                return Normal::returnCode(Normal::FAIL, "二要素验证方式【{$auth_config['auth_way']}】未参数");
            }
            if ($auth_config['auth_way'] == self::AUTH_TENCENT) {
                //腾讯二要素 验证
                return self::tencentAuth($param);
            }
        }
    }

    /**
     * 腾讯二要素验证
     * @param $param
     * @return array
     */
    public static function tencentAuth($param) {
        $config = SystemCacheConfigService::instance()->getCacheInfoBySystemCode('auth_tencent');
        if (empty($config)) {
            return Normal::returnCode(Normal::FAIL, "腾讯二要素验证参数未配置");
        }
        //检查对应字段
        $fields = ['secretKey', 'secretId', 'apiURL'];
        $res    = SystemCacheConfigService::instance()->checkAllowApiColumnsByFields($config, $fields);
        if ($res['code'] != Normal::SUC) {
            return $res;
        }
        $secret_id  = $config['secretId'];
        $secret_key = $config['secretKey'];
        $token      = $config['token'] ?? "";
        $service    = "faceid";
        $host       = "faceid.tencentcloudapi.com";
        $req_region = $config['req_region'] ?? "";;
        $version   = "2018-03-01";
        $action    = "IdCardVerification";
        $data      = [
            "IdCard" => $param['idNum'],
            "Name"   => $param['name'],
        ];
        $payload   = json_encode($data);
        $algorithm = "TC3-HMAC-SHA256";
        $timestamp = time();
        $date      = gmdate("Y-m-d", $timestamp);
        // ************* 步骤 1：拼接规范请求串 *************
        $http_request_method    = "POST";
        $canonical_uri          = "/";
        $canonical_querystring  = "";
        $ct                     = "application/json; charset=utf-8";
        $canonical_headers      = "content-type:" . $ct . "\nhost:" . $host . "\nx-tc-action:" . strtolower($action) . "\n";
        $signed_headers         = "content-type;host;x-tc-action";
        $hashed_request_payload = hash("sha256", $payload);
        $canonical_request      = "$http_request_method\n$canonical_uri\n$canonical_querystring\n$canonical_headers\n$signed_headers\n$hashed_request_payload";
        // ************* 步骤 2：拼接待签名字符串 *************
        $credential_scope         = "$date/$service/tc3_request";
        $hashed_canonical_request = hash("sha256", $canonical_request);
        $string_to_sign           = "$algorithm\n$timestamp\n$credential_scope\n$hashed_canonical_request";
        // ************* 步骤 3：计算签名 *************
        $secret_date    = hash_hmac("sha256", $date, "TC3" . $secret_key, true);
        $secret_service = hash_hmac("sha256", $service, $secret_date, true);
        $secret_signing = hash_hmac("sha256", "tc3_request", $secret_service, true);
        $signature      = hash_hmac("sha256", $string_to_sign, $secret_signing);
        // ************* 步骤 4：拼接 Authorization *************
        $authorization = "$algorithm Credential=$secret_id/$credential_scope, SignedHeaders=$signed_headers, Signature=$signature";
        // ************* 步骤 5：构造并发起请求 *************
        $headers = [
            "Authorization"  => $authorization,
            "Content-Type"   => "application/json; charset=utf-8",
            "Host"           => $host,
            "X-TC-Action"    => $action,
            "X-TC-Timestamp" => $timestamp,
            "X-TC-Version"   => $version
        ];
        if ($req_region) {
            $headers["X-TC-Region"] = $req_region;
        }
        if ($token) {
            $headers["X-TC-Token"] = $token;
        }
        $header    = array_map(function ($k, $v) {
            return "$k: $v";
        }, array_keys($headers), $headers);
        $parameter = [
            [
                'tag'    => 'AuthCard',
                'uid'    => IdService::instance()->getOtherID(),
                'url'    => $config['apiURL'],
                'data'   => $data,
                'method' => 'post',
                'format' => 'json',
                'header' => $header
            ]
        ];
        $resTask   = TaskWorker::instance()->addTask($parameter);
        $res       = current($resTask);
        $return    = json_decode($res['response']['result'], true);
        if (isset($return['Response']['Result'])) {
            if ($return['Response']['Result'] == '0') {
                return Normal::returnCode(Normal::SUC, "二要素验证成功");
            }
            return Normal::returnCode(Normal::FAIL, $return['Response']['Description'] ?? '二要素验证失败');
        }
        if (isset($return['Response']['Error'])) {
            return Normal::returnCode(Normal::FAIL, $return['Response']['Error']['Message'] ?? '二要素验证失败');
        }
        return Normal::returnCode(Normal::FAIL, "二要素验证失败{$res['response']['result']}");
    }

    /**
     * 创蓝二要素验证
     * @param $param
     * @return array
     */
    public static function chuanglanAuth($param) {
        //获取系统配置
        $config = SystemCacheConfigService::instance()->getCacheInfoBySystemCode('auth');
        if (empty($config)) {
            return Normal::returnCode(Normal::FAIL, "创蓝二要素验证参数未配置");
        }
        //检查对应字段
        $fields = ['appId', 'appKey', 'api_url'];
        $res    = SystemCacheConfigService::instance()->checkAllowApiColumnsByFields($config, $fields);
        if ($res['code'] != Normal::SUC) {
            return $res;
        }
        $data      = [
            'appId'  => $config['appId'],
            'appKey' => $config['appKey'],
            'name'   => $param['name'],
            'idNum'  => $param['idNum'],
        ];
        $parameter = [
            [
                'tag'    => 'AuthCard',
                'uid'    => IdService::instance()->getOtherID(),
                'url'    => $config['api_url'],
                'data'   => $data,
                'method' => 'post',
                'format' => 'form-data',
                'header' => []
            ]
        ];
        $resTask   = TaskWorker::instance()->addTask($parameter);
        $res       = current($resTask);
        $return    = json_decode($res['response']['result'], true);
        if ($return['code'] != 200000) {
            $message = $return['message'] ?? '购买地址实名认证失败';
            return Normal::returnCode(Normal::FAIL, $message);
        }

        if ($return['data']['result'] != '01') {
            return Normal::returnCode(Normal::FAIL, '实名认证信息' . $return['data']['remark'] . ',请确认信息');
        }
        return Normal::returnCode(Normal::SUC, "二要素验证成功");
    }
}